/**
 * @file supplement.c
 * @synopsis  属于附加文件，本文件里面的函数主要是吴梦龙的函数不能满足需要
 *	      而进行个人修改的函数，目的在于最小限度的修改吴梦龙的代码
 * @author wen wjcapple@163.com
 * @version 1.0
 * @date 2017-03-03
 */

#include "supplement.h"
#include <arpa/inet.h>
#include "malloc.h"
#include "string.h"
#include <stdio.h>
#include "time.h"
#include <stdarg.h>

#include "netcard.h"
#include "freebox.h"
#include "global.h"

#ifdef __cplusplus
extern "C" {
#endif
int32_t tms_AnalyseTick_V2(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	struct glink_base *pbase_hdr;
	struct glink_addr addr;
	pbase_hdr = (struct glink_base *)(pdata + sizeof(int32_t));
	pcontext->tick++;
	if(pcontext->pgb->src == ADDR_CU)
	{
		TickCount.src_e = 0;
		goto usr_exit;
	}
#ifdef _MANAGE		// 做网管，回应全部心跳

	if (sg_echo_tick == 1) {
		printf("ack any tick fd = %d\n", pcontext->fd);
	}

#else 				// 做MCU
	addr.src = pbase_hdr->dst;
	addr.dst = pbase_hdr->src;
	addr.pkid = pbase_hdr->pkid;
	tms_Tick(pcontext->fd, &addr);						// 返回心跳       src:0x0b dst 0x0a

#endif
usr_exit:
	return 0;
}
/* --------------------------------------------------------------------------*/
/**
 * @synopsis  isValidSlot 检查槽位,通道是否合法
 *
 * @param slot 槽位
 *
 * @returns   0 合法， 1非法
 */
/* ----------------------------------------------------------------------------*/
int32_t isValidSlot_Ch(int32_t slot, int32_t ch)
{
	int32_t ret;
	ret = 1;

	if(slot >= SLOT_MIN && slot <= SLOT_MAX && ch >= CH_MIN && ch <= CH_MAX)
		ret = 0;
	else{
		ret = 1;
		PR_X("invalide slot( %d ) or ch ( %d )\n",slot);
	}

	return ret;

}
/* --------------------------------------------------------------------------*/
/**
 * @synopsis  tms_AnalyseGetAllCardType 节点管理器获取板卡类型的命令
 *
 * @param pcontext
 * @param pdata
 * @param len
 *
 * @returns  返回板卡信息组成 
 */
/* ----------------------------------------------------------------------------*/
int32_t tms_AnalyseGetAllCardType(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	
	if (pcontext->ptcb->pf_OnGetAllCardType)
		pcontext->ptcb->pf_OnGetAllCardType(pcontext);

	return 0;
}
static void tms_Conv_Mx4Byte(
    uint32_t *pout,
    uint32_t *pin,
    int32_t count)
{
	register int32_t *p32s, *p32d;
	register int loop;



	loop = count >> 2;	// 计算有多少个4Byte数据
	// printf("loop %d\n", loop);
	p32d = (int32_t *)pout;
	p32s = (int32_t *)pin;
	for (register int i = 0; i < loop; i++) {
		*p32d = htonl(*p32s);
		p32d++;
		p32s++;
	}
}
/* --------------------------------------------------------------------------*/
/**
 * @synopsis  tms_RetAllCardType 返回节点名称和办卡类型
 *
 * @param pcontext
 * @param paddr
 * @param phead
 * @param pcard_type
 *
 * @returns   
 */
/* ----------------------------------------------------------------------------*/
int32_t tms_RetAllCardType(struct tms_context *pcontext, 
		struct glink_addr *paddr,
		struct tms_ret_card_type_head *phead, 
		struct tms_ret_card_type *pcard_type)
{
	struct tms_ret_card_type_head head; 
	struct tms_ret_card_type card_type;
	struct glink_base base_hdr;
	int32_t fd, len, card_num;
	uint32_t cmdid;
	
	card_num = phead->slot_num;

	if(card_num < 0 || card_num > 1){
		PR_X(" card_num( %d ) invalide \n", card_num);
		return -1;
	}

	cmdid = ID_RET_CARD_INFO;
	len = sizeof(struct tms_ret_card_type_head) + sizeof(struct tms_ret_card_type);



	memset(&head, 0, sizeof( struct tms_ret_card_type_head));
	fd = pcontext->fd;
	strncpy(head.ip, phead->ip, 15);
	strncpy(head.name, phead->name,63);
	head.slot_num = htonl(phead->slot_num);

	tms_Conv_Mx4Byte(&card_type, pcard_type, sizeof(struct tms_ret_card_type));

	tms_FillGlinkFrame(&base_hdr, paddr);
	glink_Build(&base_hdr, cmdid, len);

	pthread_mutex_lock(&pcontext->mutex);
	glink_SendHead(fd, &base_hdr);
	glink_SendSerial(fd, (uint8_t *)(&head), sizeof(struct tms_ret_card_type_head));
	glink_SendSerial(fd, (uint8_t *) (&card_type), sizeof( struct tms_ret_card_type));
	glink_SendTail(fd);
	pthread_mutex_unlock(&pcontext->mutex);

	return 0;


}

/* --------------------------------------------------------------------------*/
/**
 * @synopsis  tms_RetCardType_V1 单板向CU报告设备类型
 *
 * @param pcontext
 * @param paddr
 * @param pcard_type
 *
 * @returns   
 */
/* ----------------------------------------------------------------------------*/
int32_t tms_RetCardType_V1(struct tms_context *pcontext, 
		struct glink_addr *paddr,
		struct tms_ret_card_type *pcard_type)
{
	struct tms_ret_card_type card_type;
	struct glink_base base_hdr;
	int32_t fd, len;
	uint32_t cmdid;

	len = sizeof(struct tms_ret_card_type);


	cmdid = ID_RET_SINGLE_CARD_TYPE;
	fd = pcontext->fd;

	tms_Conv_Mx4Byte(&card_type, pcard_type, sizeof(struct tms_ret_card_type));

	tms_FillGlinkFrame(&base_hdr, paddr);
	glink_Build(&base_hdr, cmdid, len);

	pthread_mutex_lock(&pcontext->mutex);

	glink_SendHead(fd, &base_hdr);
	glink_SendSerial(fd, (uint8_t *) (&card_type), sizeof( struct tms_ret_card_type));
	glink_SendTail(fd);

	pthread_mutex_unlock(&pcontext->mutex);

	return 0;


}
int32_t tms_AnalyseGetSoftv(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	
	if (pcontext->ptcb->pf_OnGetSoftv)
		pcontext->ptcb->pf_OnGetSoftv(pcontext);

	return 0;
}
int32_t tms_RetSoftv(struct tms_context *pcontext,struct glink_addr *paddr, struct tms_soft_version * psoftv)
{
	struct tms_soft_version softv;
	struct glink_base base_hdr;
	int32_t len, fd;

	fd = pcontext->fd;
	softv.slot = htonl(psoftv->slot);
	softv.type = htonl(psoftv->type);
	memcpy(softv.version, psoftv->version, 256);

	tms_FillGlinkFrame(&base_hdr, paddr);
	len = sizeof(struct tms_soft_version);
	glink_Build(&base_hdr, ID_RET_SOFT_VERSION, len);

	pthread_mutex_lock(&pcontext->mutex);

	glink_SendHead(fd, &base_hdr);
	glink_SendSerial(fd, (uint8_t *) (&softv), sizeof( struct tms_soft_version));
	glink_SendTail(fd);

	pthread_mutex_unlock(&pcontext->mutex);


	return 0;
}
int32_t tms_AnalyseClrFiberCfg(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	struct tms_card_head *pcard_head;
	struct tms_card_head card_head;
	int32_t ret;

	pcard_head = (struct tms_card_head *) (pdata + GLINK_OFFSET_DATA);
	tms_Conv_Mx4Byte(&card_head, pcard_head,sizeof(struct tms_card_head));
	ret = isValidSlot_Ch(card_head.slot, card_head.pipe);

	if(ret){
		ret = CMD_RET_PARA_INVLADE;
		printf("Func: %s, Line: %d slot (%d) or ch (%d) error\n", __FUNCTION__, __LINE__,\
				card_head.slot, card_head.pipe);
		goto fail;
	}
	ret = 0;

	
	if (pcontext->ptcb->pf_OnClrFiberCfg)
		pcontext->ptcb->pf_OnClrFiberCfg(pcontext,&card_head);
fail:

	return 0;
}
int32_t tms_AnalyseGetFiberCfg(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	struct tms_card_head *pcard_head;
	struct tms_card_head card_head;
	int32_t ret;

	pcard_head = (struct tms_card_head *) (pdata + GLINK_OFFSET_DATA);
	tms_Conv_Mx4Byte(&card_head, pcard_head,sizeof(struct tms_card_head));
	ret = isValidSlot_Ch(card_head.slot, card_head.pipe);

	if(ret){
		ret = CMD_RET_PARA_INVLADE;
		printf("Func: %s, Line: %d slot (%d) or ch (%d) error\n", __FUNCTION__, __LINE__,\
				card_head.slot, card_head.pipe);
		goto fail;
	}
	ret = 0;

	
	if (pcontext->ptcb->pf_OnGetFiberCfg)
		pcontext->ptcb->pf_OnGetFiberCfg(pcontext,&card_head);
fail:

	return 0;
}
int32_t tms_AnalyseGetCurAlarm(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	struct tms_get_alarm *pget_alarm;
	int32_t ret;

	pget_alarm = (struct tms_get_alarm*) (pdata + GLINK_OFFSET_DATA);
	tms_Conv_Mx4Byte(pget_alarm, pget_alarm,sizeof(struct tms_get_alarm));
	ret = isValidSlot_Ch(pget_alarm->slot, 0);

	if(ret){
		ret = CMD_RET_PARA_INVLADE;
		printf("Func: %s, Line: %d slot (%d) error\n", __FUNCTION__, __LINE__,\
				pget_alarm->slot);
		goto fail;
	}
	ret = 0;

	
	if (pcontext->ptcb->pf_OnCurAlarm)
		pcontext->ptcb->pf_OnCurAlarm(pcontext,pget_alarm);
fail:

	return 0;
}
int32_t tms_RetFpgaInfo(struct tms_context *pcontext,
		struct glink_addr *paddr, 
		struct tms_setotdrfpgainfo *pfpga_info)
{
	struct tms_setotdrfpgainfo fpga_info;
	struct glink_base base_hdr;
	int32_t len, fd;

	fd = pcontext->fd;
	memcpy(&fpga_info, pfpga_info, sizeof(struct tms_setotdrfpgainfo));
	len = sizeof(struct tms_setotdrfpgainfo);
	tms_Conv_Mx4Byte((uint32_t *)(&fpga_info), (uint32_t *)(&fpga_info), len-20);
	fpga_info.reserved0 = htonl(fpga_info.reserved0);
	
	tms_FillGlinkFrame(&base_hdr, paddr);
	glink_Build(&base_hdr, ID_RET_PIPE_PARA, len);

	pthread_mutex_lock(&pcontext->mutex);

	glink_SendHead(fd, &base_hdr);
	glink_SendSerial(fd, (uint8_t *) (&fpga_info), len);
	glink_SendTail(fd);

	pthread_mutex_unlock(&pcontext->mutex);


	return 0;
}
int32_t tms_AnalyseGetOTDRFPGAInfo(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	struct tms_card_head *pcard_head;
	int32_t ret;

	pcard_head = (struct tms_card_head*) (pdata + GLINK_OFFSET_DATA);
	tms_Conv_Mx4Byte(pcard_head, pcard_head,sizeof(struct tms_card_head));
	ret = isValidSlot_Ch(pcard_head->slot, pcard_head->pipe);

	if(ret){
		ret = CMD_RET_PARA_INVLADE;
		printf("Func: %s, Line: %d slot (%d) or pipe (%d) error\n", __FUNCTION__, __LINE__,\
				pcard_head->slot, pcard_head->pipe);
		goto fail;
	}
	ret = 0;

	
	if (pcontext->ptcb->pf_OnGetOTDRFPGAInfo)
		pcontext->ptcb->pf_OnGetOTDRFPGAInfo(pcontext,pcard_head);
fail:

	return 0;
}


int32_t tms_initFdManage()
{
	pthread_mutex_init(&SockFdMange.mutex, NULL);
	SockFdMange.num = 0;
	memset(&SockFdMange.buf[0], 0, sizeof(struct tms_FdSockt)*MAX_CONNECT_NUM);
	return 0;
}
int32_t tms_SelectContextByAddr(int32_t addr, struct tms_context **pcontext)
{
	int32_t fd, ret, i;
	fd = 0;
	ret = 1;
	assert(addr != 0);
	*pcontext = NULL;
	pthread_mutex_lock(&SockFdMange.mutex);
	for(i = 0; i < MAX_CONNECT_NUM;i++)
	{
		if(addr == SockFdMange.buf[i].addr)
			fd = SockFdMange.buf[i].fd;
	}
	pthread_mutex_unlock(&SockFdMange.mutex);
	if(fd == -1)
		return ret;

	return tms_SelectContextByFD(fd, pcontext);
}
int32_t tms_SelectFdByAddr(int32_t addr)
{
	int32_t fd, i;
	fd = -1;
	assert(addr != 0);

	pthread_mutex_lock(&SockFdMange.mutex);
	for(i = 0; i < MAX_CONNECT_NUM;i++)
	{
		if(addr == SockFdMange.buf[i].addr)
			fd = SockFdMange.buf[i].fd;
	}
	pthread_mutex_unlock(&SockFdMange.mutex);

	return fd ;
}

int32_t tms_RefreshAddrFd(int32_t fd, int32_t addr)
{
	int32_t i, index;
	
	pthread_mutex_lock(&SockFdMange.mutex);
	if(SockFdMange.num == 0){
		SockFdMange.buf[0].addr = addr;
		SockFdMange.buf[0].fd = fd;
		SockFdMange.num++;
		goto usr_exit;
	}

	for(i = 0; i < MAX_CONNECT_NUM;i++)
	{
		if(addr == SockFdMange.buf[i].addr){
			SockFdMange.buf[i].fd = fd;
			break;
		}

	}
	//当前找不到匹配，那么新增
	if(i == MAX_CONNECT_NUM && SockFdMange.num < MAX_CONNECT_NUM){
		index = SockFdMange.num;
		SockFdMange.buf[index].addr = addr;
		SockFdMange.buf[index].fd = fd;
		SockFdMange.num++;
	}
usr_exit:
	pthread_mutex_unlock(&SockFdMange.mutex);
	return 0;

}
/* --------------------------------------------------------------------------*/
/**
 * @synopsis  tms_ClrAddrFd 如果fd被关闭，需要将和该fd关联的addr清空
 *
 * @param fd
 *
 * @returns   
 */
/* ----------------------------------------------------------------------------*/
int32_t tms_ClrAddrFd(int32_t fd)
{
	int32_t i;
	assert(fd > 0);
	pthread_mutex_lock(&SockFdMange.mutex);

	for(i = 0; i < MAX_CONNECT_NUM;i++)
	{
		if(fd == SockFdMange.buf[i].fd){
			SockFdMange.buf[i].addr = 0;
			SockFdMange.buf[i].fd = 0;
			SockFdMange.num --;
		}

	}

	pthread_mutex_unlock(&SockFdMange.mutex);

	return 0;

}
int32_t rcv_update_sh(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	// todo 通知ui
	struct tms_hebei2_update_hdr *pver_hdr;
	char *pfile;
	struct tms_hebei2_update_md5 *pmd5;
	char strmd5[17];
	struct tms_ack ack;
	struct glink_addr addr;
	char *pc, elf_id[24];
	char *pc_tar;
	char sh_name[24];
	char tmp_path[64];
	char dst_path[64], cmd_line[128];
	int ret, bytes;

	memset(&ack, 0, sizeof(struct tms_ack));
	addr.dst = pcontext->pgb->src;
	addr.src = ADDR_LOCAL;
	addr.pkid = pcontext->pgb->pkid;
	ack.cmdid = pcontext->pgb->cmdid;
	ack.slot = card_slot;

	pver_hdr = (struct tms_hebei2_update_hdr *)(pdata + GLINK_OFFSET_DATA);

	pfile = (char*)(pver_hdr + 1);
	pmd5 = (struct tms_hebei2_update_md5*)(pfile + pver_hdr->flen);
	memcpy(strmd5, pmd5->md5, 16);
	strmd5[16] = '\0';

	
	pc = strstr(pver_hdr->fname, ".exe");
	pc_tar = strstr(pver_hdr->fname, "update.tar");
	if(strlen(pver_hdr->fname) > 256|| pc == NULL || pc_tar == NULL)
	{
		printf("file name to over 256 or not find hoped str .tar update or tar in %s \n", \
				pver_hdr->fname);
		ret = 5;
		goto fail;
	}

	memset(tmp_path, 0, sizeof(tmp_path));
	memset(dst_path, 0, sizeof(dst_path));
	memset(cmd_line, 0, sizeof(cmd_line));

	bytes = pc - pver_hdr->fname;
	memset(sh_name, 0, sizeof(sh_name));
	memcpy(sh_name, pver_hdr->fname, bytes);
	snprintf(tmp_path, 64,"/tmp/%s\0",sh_name);
	snprintf(dst_path, 64,"/uptarfile/update/%s\0",sh_name);

	FILE *fp = fopen(tmp_path, "wb");
	fwrite(pfile, 1, pver_hdr->flen, fp);
	fclose(fp);



	// 本地计算MD5
	char strout[256];
	snprintf(cmd_line, 128, "md5sum %s\0", tmp_path);

	//fp = popen("md5sum /tmp/tmp.tar", "r");
	fp = popen(cmd_line, "r");
	ret = fread( strout, sizeof(char), sizeof(strout) - 1, fp);
	fclose(fp);


	strout[ret] = '\0';
	strout[16] = '\0';
	

	// 比较MD5
	ret = strncmp(strout, strmd5, 16);
	if (0 == ret) {
		ack.errcode = ret;
		tms_AckEx(pcontext->fd, &addr, &ack);


		
		snprintf(cmd_line, 128, "cp %s %s\0", tmp_path, dst_path);
		//system("cp /tmp/tmp.tar /uptarfile/update/update.tar");
		system(cmd_line);
		//system("chmod +x /app/update/update.tar");
		printf("接收成功\n");
		sleep(1);
		system("sync");
		// 传输完后断开链接
		close(pcontext->fd);
#ifndef TARGET_X86
		printf("3秒后系统开始升级\n");
		//system("reboot");
		sleep(3);
		system("reboot");
		exit(0);
#endif

	}
	
fail:	
	ack.errcode = ret;
	tms_AckEx(pcontext->fd, &addr, &ack);


	return 0;

}
int32_t rcv_app_elf(struct tms_context *pcontext, int8_t *pdata, int32_t len)
{
	// todo 通知ui
	struct tms_hebei2_update_hdr *pver_hdr;
	char *pfile;
	struct tms_hebei2_update_md5 *pmd5;
	char strmd5[17];
	struct tms_ack ack;
	struct glink_addr addr;
	char *pc, elf_id[24];
	int ret;

	memset(&ack, 0, sizeof(struct tms_ack));
	addr.dst = pcontext->pgb->src;
	addr.src = ADDR_LOCAL;
	addr.pkid = pcontext->pgb->pkid;
	ack.cmdid = pcontext->pgb->cmdid;
	ack.slot = card_slot;

	pver_hdr = (struct tms_hebei2_update_hdr *)(pdata + GLINK_OFFSET_DATA);

	pfile = (char*)(pver_hdr + 1);
	pmd5 = (struct tms_hebei2_update_md5*)(pfile + pver_hdr->flen);
	memcpy(strmd5, pmd5->md5, 16);
	strmd5[16] = '\0';

	memset(elf_id, 0, sizeof(elf_id));
	memcpy(elf_id, pfile, 16);
	pc = strstr(elf_id, "ELF");
	if(pc == NULL){
		pc = strstr(elf_id, "elf");
		if(pc == NULL){
			printf("not find hoped str elf or ELF in %s \n", elf_id);
			PrintfMemory(elf_id, 16);
			ret = 5;
			goto fail;
		}
	}


	FILE *fp = fopen("/tmp/tmp.elf", "wb");
	fwrite(pfile, 1, pver_hdr->flen, fp);
	fclose(fp);



	// 本地计算MD5
	char strout[256];

	fp = popen("md5sum /tmp/tmp.elf", "r");
	ret = fread( strout, sizeof(char), sizeof(strout) - 1, fp);
	fclose(fp);


	strout[ret] = '\0';
	strout[16] = '\0';
	

	// 比较MD5
	ret = strncmp(strout, strmd5, 16);
	if (0 == ret) {
		ack.errcode = ret;
		tms_AckEx(pcontext->fd, &addr, &ack);



		system("cp /tmp/tmp.elf /app/update/wjc.elf");
		system("chmod +x /app/update/wjc.elf");
		printf("升级成功\n");
		sleep(1);
		system("sync");
		// 传输完后断开链接
		close(pcontext->fd);
		sleep(3);
#ifndef TARGET_X86
		printf("3秒后旧程序退出，自动运行新程序\n");
		//system("reboot");
		sleep(3);
		exit(0);
#endif

	}
	
fail:	
	ack.errcode = ret;
	tms_AckEx(pcontext->fd, &addr, &ack);


	return 0;
}









#ifdef __cplusplus
}
#endif
